home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / mac / DirectX SDK / DXSDK / samples / Multimedia / DirectPlay / VoiceConnect / voiceconnect.cpp < prev    next >
C/C++ Source or Header  |  2001-10-31  |  56KB  |  1,384 lines

  1. //----------------------------------------------------------------------------
  2. // File: VoiceConnect.cpp
  3. //
  4. // Desc: The main file for VoiceConnect that shows how use DirectPlay along 
  5. //       with DirectPlayVoice to allow talking in a conference situation. 
  6. //
  7. // Copyright (c) 1999-2001 Microsoft Corp. All rights reserved.
  8. //-----------------------------------------------------------------------------
  9. #define STRICT
  10. #include <windows.h>
  11. #include <basetsd.h>
  12. #include <dxerr8.h>
  13. #include <dplay8.h>
  14. #include <dplobby8.h>
  15. #include <dvoice.h>
  16. #include <commctrl.h>
  17. #include <cguid.h>
  18. #include "NetConnect.h"
  19. #include "NetVoice.h"
  20. #include "DXUtil.h"
  21. #include "resource.h"
  22.  
  23.  
  24.  
  25.  
  26. //-----------------------------------------------------------------------------
  27. // Player context locking defines
  28. //-----------------------------------------------------------------------------
  29. CRITICAL_SECTION g_csPlayerContext;
  30. #define PLAYER_LOCK()                   EnterCriticalSection( &g_csPlayerContext ); 
  31. #define PLAYER_ADDREF( pPlayerInfo )    if( pPlayerInfo ) pPlayerInfo->lRefCount++;
  32. #define PLAYER_RELEASE( pPlayerInfo )   if( pPlayerInfo ) { pPlayerInfo->lRefCount--; if( pPlayerInfo->lRefCount <= 0 ) SAFE_DELETE( pPlayerInfo ); }
  33. #define PLAYER_UNLOCK()                 LeaveCriticalSection( &g_csPlayerContext );
  34.  
  35.  
  36. //-----------------------------------------------------------------------------
  37. // Defines, and constants
  38. //-----------------------------------------------------------------------------
  39. #define DPLAY_SAMPLE_KEY        TEXT("Software\\Microsoft\\DirectX DirectPlay Samples")
  40. #define MAX_PLAYER_NAME         14
  41. #define WM_APP_DISPLAY_PLAYERS  (WM_APP + 0)
  42.  
  43. // This GUID allows DirectPlay to find other instances of the same game on
  44. // the network.  So it must be unique for every game, and the same for 
  45. // every instance of that game.  // {FCD4761E-2B9C-4478-B7EA-D9E18E6E2AAC}
  46. GUID g_guidApp = { 0xfcd4761e, 0x2b9c, 0x4478, { 0xb7, 0xea, 0xd9, 0xe1, 0x8e, 0x6e, 0x2a, 0xac } };
  47.  
  48.  
  49.  
  50.  
  51. //-----------------------------------------------------------------------------
  52. // Global variables
  53. //-----------------------------------------------------------------------------
  54. struct APP_PLAYER_INFO
  55. {
  56.     LONG  lRefCount;                        // Ref count so we can cleanup when all threads 
  57.                                             // are done w/ this object
  58.     DPNID dpnidPlayer;                      // DPNID of player
  59.     BOOL  bTalking;                         // Is the player talking
  60.     BOOL  bHalfDuplex;                      // If true, then player cannot talk
  61.     TCHAR strPlayerName[MAX_PLAYER_NAME];   // Player name
  62. };
  63.  
  64.  
  65. IDirectPlay8Peer*  g_pDP                         = NULL;    // DirectPlay peer object
  66. CNetConnectWizard* g_pNetConnectWizard           = NULL;    // Connection wizard
  67. IDirectPlay8LobbiedApplication* g_pLobbiedApp    = NULL;    // DirectPlay lobbied app 
  68. BOOL               g_bWasLobbyLaunched           = FALSE;   // TRUE if lobby launched
  69. CNetVoice*         g_pNetVoice                   = NULL;    // DirectPlay voice helper class
  70. HINSTANCE          g_hInst                       = NULL;    // HINST of app
  71. HWND               g_hDlg                        = NULL;    // HWND of main dialog
  72. TCHAR              g_strAppName[256]             = TEXT("VoiceConnect");
  73. BOOL               g_bVoiceSessionInProgress     = FALSE;   // True if voice has been init'ed
  74. DPNID*             g_pPlayers                    = NULL;    // Array of DPNIDs
  75. DWORD              g_dwPlayersArraySize          = 0;       // Size of g_pPlayers
  76. HRESULT            g_hrDialog;                              // Exit code for app 
  77. TCHAR              g_strLocalPlayerName[MAX_PATH];          // Local player name
  78. TCHAR              g_strSessionName[MAX_PATH];              // Session name
  79. TCHAR              g_strPreferredProvider[MAX_PATH];        // Provider string
  80. BOOL               g_bHostPlayer;                           // TRUE if local player is host
  81. DPNID              g_LocalPlayerDPNID;                      // DPNID of local player
  82. GUID               g_guidDVSessionCT;                       // GUID for choosen voice compression
  83. DVCLIENTCONFIG     g_dvClientConfig;                        // Voice client config
  84.  
  85.  
  86.  
  87.  
  88. //-----------------------------------------------------------------------------
  89. // Function-prototypes
  90. //-----------------------------------------------------------------------------
  91. INT_PTR CALLBACK VoiceDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  92. HRESULT          InitDirectPlay();
  93. HRESULT          OnInitDialog( HWND hDlg );
  94. HRESULT          DisplayPlayersInChat( HWND hDlg );
  95. HRESULT WINAPI   DirectPlayMessageHandler( LPVOID lpvUserContext, DWORD dwMessageType, LPVOID lpMessage );
  96. HRESULT WINAPI   DirectPlayLobbyMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  97. HRESULT WINAPI   DirectPlayVoiceClientMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  98. HRESULT WINAPI   DirectPlayVoiceServerMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  99. void             SetPlayerTalking( APP_PLAYER_INFO *pPlayerInfo, BOOL bTalking );
  100. INT_PTR CALLBACK VoiceConfigDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  101. HRESULT          VoiceConfigEnumCompressionCodecs( HWND hDlg );
  102. VOID             VoiceConfigDlgOnOK( HWND hDlg );
  103.  
  104.  
  105.  
  106.  
  107. //-----------------------------------------------------------------------------
  108. // Name: WinMain()
  109. // Desc: Entry point for the application.  Since we use a simple dialog for 
  110. //       user interaction we don't need to pump messages.
  111. //-----------------------------------------------------------------------------
  112. INT APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, 
  113.                       INT nCmdShow )
  114. {
  115.     HRESULT hr;
  116.     HKEY    hDPlaySampleRegKey;
  117.     BOOL    bConnectSuccess = FALSE;
  118.  
  119.     g_hInst = hInst;
  120.     InitializeCriticalSection( &g_csPlayerContext );
  121.  
  122.     // Init player ID array 
  123.     g_dwPlayersArraySize = 10;
  124.     g_pPlayers = (DPNID*) malloc( sizeof(DPNID)*g_dwPlayersArraySize );
  125.  
  126.     // Read persistent state information from registry
  127.     RegCreateKeyEx( HKEY_CURRENT_USER, DPLAY_SAMPLE_KEY, 0, NULL,
  128.                     REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, 
  129.                     &hDPlaySampleRegKey, NULL );
  130.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Player Name"), 
  131.                              g_strLocalPlayerName, MAX_PATH, TEXT("TestPlayer") );
  132.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Session Name"), 
  133.                              g_strSessionName, MAX_PATH, TEXT("TestGame") );
  134.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Preferred Provider"), 
  135.                              g_strPreferredProvider, MAX_PATH, 
  136.                              TEXT("DirectPlay8 TCP/IP Service Provider") );
  137.  
  138.     InitCommonControls();
  139.  
  140.     // Init COM so we can use CoCreateInstance
  141.     CoInitializeEx( NULL, COINIT_MULTITHREADED );
  142.  
  143.     // Create helper class
  144.     g_pNetConnectWizard = new CNetConnectWizard( hInst, NULL, g_strAppName, &g_guidApp );
  145.     g_pNetVoice         = new CNetVoice( DirectPlayVoiceClientMessageHandler, DirectPlayVoiceServerMessageHandler );
  146.  
  147.     if( FAILED( hr = InitDirectPlay() ) )
  148.     {
  149.         DXTRACE_ERR( TEXT("InitDirectPlay"), hr );
  150.         MessageBox( NULL, TEXT("Failed initializing IDirectPlay8Peer. ")
  151.                     TEXT("The sample will now quit."),
  152.                     TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  153.         return FALSE;
  154.     }
  155.  
  156.     // Check if we were launched from a lobby client
  157.     if( g_bWasLobbyLaunched && g_pNetConnectWizard->HaveConnectionSettingsFromLobby() )
  158.     {
  159.         // If were lobby launched then DPL_MSGID_CONNECT has already been
  160.         // handled, so we can just tell the wizard to connect to the lobby
  161.         // that has sent us a DPL_MSGID_CONNECT msg.
  162.         if( FAILED( hr = g_pNetConnectWizard->ConnectUsingLobbySettings() ) )
  163.         {
  164.             DXTRACE_ERR( TEXT("ConnectUsingLobbySettings"), hr );
  165.             MessageBox( NULL, TEXT("Failed to connect using lobby settings. ")
  166.                         TEXT("The sample will now quit."),
  167.                         TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  168.  
  169.             bConnectSuccess = FALSE;
  170.         }
  171.         else
  172.         {
  173.             // Read information from g_pNetConnectWizard
  174.             _tcscpy( g_strLocalPlayerName, g_pNetConnectWizard->GetPlayerName() );
  175.             g_bHostPlayer = g_pNetConnectWizard->IsHostPlayer();
  176.  
  177.             bConnectSuccess = TRUE; 
  178.         }
  179.     }
  180.     else
  181.     {
  182.         // If not lobby launched, prompt the user about the network 
  183.         // connection and which session they would like to join or 
  184.         // if they want to create a new one.
  185.  
  186.         // Setup connection wizard
  187.         g_pNetConnectWizard->SetPlayerName( g_strLocalPlayerName );
  188.         g_pNetConnectWizard->SetSessionName( g_strSessionName );
  189.         g_pNetConnectWizard->SetPreferredProvider( g_strPreferredProvider );
  190.  
  191.         // Do the connection wizard
  192.         hr = g_pNetConnectWizard->DoConnectWizard( FALSE );        
  193.         if( FAILED( hr ) ) 
  194.         {
  195.             DXTRACE_ERR( TEXT("DoConnectWizard"), hr );
  196.             MessageBox( NULL, TEXT("Multiplayer connect failed. ")
  197.                         TEXT("The sample will now quit."),
  198.                         TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  199.             bConnectSuccess = FALSE;
  200.         } 
  201.         else if( hr == NCW_S_QUIT ) 
  202.         {
  203.             // The user canceled the Multiplayer connect, so quit 
  204.             bConnectSuccess = FALSE;
  205.         }
  206.         else
  207.         {
  208.             bConnectSuccess = TRUE; 
  209.  
  210.             // Read information from g_pNetConnectWizard
  211.             _tcscpy( g_strLocalPlayerName, g_pNetConnectWizard->GetPlayerName() );
  212.             _tcscpy( g_strSessionName, g_pNetConnectWizard->GetSessionName() );
  213.             _tcscpy( g_strPreferredProvider, g_pNetConnectWizard->GetPreferredProvider() );
  214.             g_bHostPlayer = g_pNetConnectWizard->IsHostPlayer();
  215.  
  216.             // Write information to the registry
  217.             DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Player Name"), g_strLocalPlayerName );
  218.             DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Session Name"), g_strSessionName );
  219.             DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Preferred Provider"), g_strPreferredProvider );
  220.         }
  221.     }
  222.  
  223.     if( bConnectSuccess )
  224.     {
  225.         // Set default DirectPlayVoice setup options
  226.         ZeroMemory( &g_dvClientConfig, sizeof(g_dvClientConfig) );
  227.         g_dvClientConfig.dwSize                 = sizeof(g_dvClientConfig);
  228.         g_dvClientConfig.dwFlags                = DVCLIENTCONFIG_AUTOVOICEACTIVATED |
  229.                                                   DVCLIENTCONFIG_AUTORECORDVOLUME;
  230.         g_dvClientConfig.lPlaybackVolume        = DVPLAYBACKVOLUME_DEFAULT;
  231.         g_dvClientConfig.dwBufferQuality        = DVBUFFERQUALITY_DEFAULT;
  232.         g_dvClientConfig.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT;
  233.         g_dvClientConfig.dwThreshold          = DVTHRESHOLD_UNUSED;
  234.         g_dvClientConfig.lRecordVolume          = DVRECORDVOLUME_LAST;
  235.         g_dvClientConfig.dwNotifyPeriod         = 0;
  236.  
  237.         g_guidDVSessionCT                       = DPVCTGUID_DEFAULT;
  238.  
  239.         // Ask user to change g_dvClientConfig, g_guidDVSessionCT
  240.         DWORD dwResult = (DWORD)DialogBox( hInst, MAKEINTRESOURCE(IDD_VOICE_SETUP), 
  241.                                            NULL, (DLGPROC) VoiceConfigDlgProc );
  242.     }
  243.  
  244.     if( bConnectSuccess )
  245.     {
  246.         // App is now connected via DirectPlay, so start the game.  
  247.  
  248.         // For this sample, we just start a simple dialog box game.
  249.         g_hrDialog = S_OK;
  250.         DialogBox( hInst, MAKEINTRESOURCE(IDD_MAIN_GAME), NULL, (DLGPROC) VoiceDlgProc );
  251.  
  252.         if( FAILED( g_hrDialog ) )
  253.         {
  254.             if( g_hrDialog == DPNERR_CONNECTIONLOST )
  255.             {
  256.                 MessageBox( NULL, TEXT("The DirectPlay session was lost. ")
  257.                             TEXT("The sample will now quit."),
  258.                             TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  259.             }
  260.             else
  261.             {
  262.                 DXTRACE_ERR( TEXT("DialogBox"), hr );
  263.                 MessageBox( NULL, TEXT("An error occured during the game. ")
  264.                             TEXT("The sample will now quit."),
  265.                             TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  266.             }
  267.         }
  268.     }
  269.  
  270.     // Cleanup player ID array 
  271.     free( g_pPlayers );
  272.  
  273.     // Disconnect from the DirectPlayVoice session, 
  274.     // and destory it if we are the host player.
  275.     SAFE_DELETE( g_pNetVoice ); 
  276.  
  277.     // Cleanup DirectPlay and helper classes
  278.     g_pNetConnectWizard->Shutdown();
  279.  
  280.     if( g_pDP )
  281.     {
  282.         g_pDP->Close(0);
  283.         SAFE_RELEASE( g_pDP );
  284.     }
  285.  
  286.     if( g_pLobbiedApp )
  287.     {
  288.         g_pLobbiedApp->Close( 0 );
  289.         SAFE_RELEASE( g_pLobbiedApp );
  290.     }    
  291.  
  292.     // Don't delete the wizard until we know that 
  293.     // DirectPlay is out of its message handlers.
  294.     // This will be true after Close() has been called. 
  295.     SAFE_DELETE( g_pNetConnectWizard );
  296.  
  297.     RegCloseKey( hDPlaySampleRegKey );
  298.     DeleteCriticalSection( &g_csPlayerContext );
  299.     CoUninitialize();
  300.  
  301.     return TRUE;
  302. }
  303.  
  304.  
  305.  
  306.  
  307. //-----------------------------------------------------------------------------
  308. // Name: InitDirectPlay()
  309. // Desc: 
  310. //-----------------------------------------------------------------------------
  311. HRESULT InitDirectPlay()
  312. {
  313.     DPNHANDLE hLobbyLaunchedConnection = NULL;
  314.     HRESULT hr;
  315.  
  316.     // Create IDirectPlay8Peer
  317.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Peer, NULL, 
  318.                                        CLSCTX_INPROC_SERVER,
  319.                                        IID_IDirectPlay8Peer, 
  320.                                        (LPVOID*) &g_pDP ) ) )
  321.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  322.  
  323.     // Create IDirectPlay8LobbiedApplication
  324.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8LobbiedApplication, NULL, 
  325.                                        CLSCTX_INPROC_SERVER,
  326.                                        IID_IDirectPlay8LobbiedApplication, 
  327.                                        (LPVOID*) &g_pLobbiedApp ) ) )
  328.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  329.  
  330.     // Init the helper class, now that g_pDP and g_pLobbiedApp are valid
  331.     g_pNetConnectWizard->Init( g_pDP, g_pLobbiedApp );
  332.  
  333.     // Init IDirectPlay8Peer
  334.     if( FAILED( hr = g_pDP->Initialize( NULL, DirectPlayMessageHandler, 0 ) ) )
  335.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  336.  
  337.     // Init IDirectPlay8LobbiedApplication.  Before this Initialize() returns 
  338.     // a DPL_MSGID_CONNECT msg may come in to the DirectPlayLobbyMessageHandler 
  339.     // so be prepared ahead of time.
  340.     if( FAILED( hr = g_pLobbiedApp->Initialize( NULL, DirectPlayLobbyMessageHandler, 
  341.                                                 &hLobbyLaunchedConnection, 0 ) ) )
  342.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  343.  
  344.     // IDirectPlay8LobbiedApplication::Initialize returns a handle to a connnection
  345.     // if we have been lobby launced.  Initialize is guanteeded to return after 
  346.     // the DPL_MSGID_CONNECT msg has been processed.  So unless a we are expected 
  347.     // multiple lobby connections, we do not need to remember the lobby connection
  348.     // handle since it will be recorded upon the DPL_MSGID_CONNECT msg.
  349.     g_bWasLobbyLaunched = ( hLobbyLaunchedConnection != NULL );
  350.  
  351.     return S_OK;
  352. }
  353.  
  354.  
  355.  
  356.  
  357. //-----------------------------------------------------------------------------
  358. // Name: VoiceDlgProc()
  359. // Desc: Handles dialog messages
  360. //-----------------------------------------------------------------------------
  361. INT_PTR CALLBACK VoiceDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  362. {
  363.     switch( msg ) 
  364.     {
  365.         case WM_INITDIALOG:
  366.             {
  367.                 g_hDlg = hDlg;
  368.  
  369.                 if( FAILED( g_hrDialog = g_pNetVoice->Init( hDlg, g_bHostPlayer, TRUE,
  370.                                                             g_pDP, DVSESSIONTYPE_PEER, 
  371.                                                             &g_guidDVSessionCT, &g_dvClientConfig ) ) )
  372.                 {
  373.                     if( g_hrDialog == DVERR_USERBACK )
  374.                     {
  375.                         MessageBox( hDlg, TEXT("The user backed out of the wizard.  ")
  376.                                     TEXT("This simple sample does not handle this case, so ")
  377.                                     TEXT("the sample will quit."), TEXT("DirectPlay Sample"), MB_OK );
  378.                         g_hrDialog = S_OK;
  379.                     }
  380.  
  381.                     if( g_hrDialog == DVERR_USERCANCEL )
  382.                     {
  383.                         MessageBox( hDlg, TEXT("The user canceled the wizard. ")
  384.                                     TEXT("This simple sample does not handle this case, so ")
  385.                                     TEXT("the sample will quit."), TEXT("DirectPlay Sample"), MB_OK );
  386.                         g_hrDialog = S_OK;
  387.                     }
  388.  
  389.                     if( g_hrDialog == DVERR_ALREADYPENDING )
  390.                     {
  391.                         MessageBox( hDlg, TEXT("Another instance of the Voice Setup Wizard is already running. ")
  392.                                     TEXT("This simple sample does not handle this case, so ")
  393.                                     TEXT("the sample will quit."), TEXT("DirectPlay Sample"), MB_OK );
  394.                         g_hrDialog = S_OK;
  395.                     }
  396.  
  397.                     if( FAILED(g_hrDialog) ) 
  398.                         DXTRACE_ERR( TEXT("Init"), g_hrDialog );
  399.  
  400.                     EndDialog( hDlg, 0 );
  401.                     break;
  402.                 }
  403.  
  404.                 if( g_pNetVoice->IsHalfDuplex() ) 
  405.                 {
  406.                     MessageBox( hDlg, TEXT("You are running in half duplex mode. ")
  407.                                 TEXT("In half duplex mode no recording takes place."), 
  408.                                 TEXT("DirectPlay Sample"), MB_OK );
  409.                 }
  410.  
  411.                 g_bVoiceSessionInProgress = TRUE;
  412.  
  413.                 if( FAILED( g_hrDialog = OnInitDialog( hDlg ) ) )
  414.                 {
  415.                     DXTRACE_ERR( TEXT("OnInitDialog"), g_hrDialog );
  416.                     EndDialog( hDlg, 0 );
  417.                     break;
  418.                 }
  419.             }
  420.             break;
  421.  
  422.         case WM_COMMAND:
  423.             switch( LOWORD(wParam) )
  424.             {
  425.                 case IDC_SETUP:
  426.                     {
  427.                         // Ask the user for DirectPlayVoice setup params
  428.                         DWORD dwResult = (DWORD)DialogBox( g_hInst, 
  429.                                                            MAKEINTRESOURCE(IDD_VOICE_SETUP), 
  430.                                                            hDlg, (DLGPROC) VoiceConfigDlgProc );
  431.                         if( dwResult != IDCANCEL )
  432.                             g_pNetVoice->ChangeVoiceClientSettings( &g_dvClientConfig );
  433.                     }
  434.                     return TRUE;
  435.  
  436.                 case IDCANCEL:
  437.                     g_hrDialog = S_OK;
  438.                     EndDialog( hDlg, 0 );
  439.                     return TRUE;
  440.             }
  441.             break;
  442.  
  443.         case WM_APP_DISPLAY_PLAYERS:
  444.         {
  445.             DisplayPlayersInChat( hDlg );
  446.             break;
  447.         }
  448.  
  449.         case WM_TIMER:
  450.         {
  451.             DWORD            dwNumPlayers;
  452.             DWORD            iIndex;
  453.             LVITEM           lvItem;
  454.             APP_PLAYER_INFO* pPlayerInfo = NULL;
  455.             HWND             hListView = GetDlgItem( hDlg, IDC_PEOPLE_LIST );
  456.  
  457.             dwNumPlayers = ListView_GetItemCount( hListView );
  458.  
  459.             // Now that they are added and the listview sorted them by name,
  460.             // run through them all caching the listview index with its dpnid
  461.             for( iIndex = 0; iIndex < dwNumPlayers; iIndex++ )
  462.             {
  463.                 HRESULT hr;
  464.                 APP_PLAYER_INFO* pPlayerInfo = NULL;
  465.                 DPNID dpnidPlayer;
  466.  
  467.                 lvItem.mask  = LVIF_PARAM;
  468.                 lvItem.iItem = iIndex;
  469.                 ListView_GetItem( hListView, &lvItem );
  470.  
  471.                 dpnidPlayer = (DPNID) lvItem.lParam;
  472.  
  473.                 PLAYER_LOCK(); // enter player context CS
  474.  
  475.                 // Get the player context accosicated with this DPNID
  476.                 hr = g_pDP->GetPlayerContext( dpnidPlayer, 
  477.                                               (LPVOID* const) &pPlayerInfo,
  478.                                               0);
  479.  
  480.  
  481.                 PLAYER_ADDREF( pPlayerInfo ); // addref player, since we are using it now
  482.                 PLAYER_UNLOCK(); // leave player context CS
  483.  
  484.                 if( FAILED(hr) || pPlayerInfo == NULL )
  485.                 {
  486.                     // The player who sent this may have gone away before this 
  487.                     // message was handled, so just ignore it
  488.                     continue;
  489.                 }
  490.  
  491.                 TCHAR strStatus[255];
  492.  
  493.                 if( pPlayerInfo->bHalfDuplex )
  494.                 {
  495.                     _tcscpy( strStatus, TEXT("Can't talk") );
  496.                 }
  497.                 else
  498.                 {
  499.                     if( pPlayerInfo->bTalking )
  500.                         _tcscpy( strStatus, TEXT("Talking") );
  501.                     else
  502.                         _tcscpy( strStatus, TEXT("Silent") );
  503.                 }
  504.  
  505.                 lvItem.iItem      = iIndex;
  506.                 lvItem.iSubItem   = 1;
  507.                 lvItem.mask       = LVIF_TEXT;
  508.                 lvItem.pszText    = strStatus;
  509.  
  510.                 PLAYER_LOCK();
  511.                 PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  512.                 PLAYER_UNLOCK();
  513.  
  514.                 SendMessage( hListView, LVM_SETITEM, 0, (LPARAM) &lvItem );
  515.             }
  516.             break;
  517.         }
  518.     }
  519.  
  520.     return FALSE; // Didn't handle message
  521. }
  522.  
  523.  
  524.  
  525.  
  526. //-----------------------------------------------------------------------------
  527. // Name: OnInitDialog()
  528. // Desc: Inits the dialog 
  529. //-----------------------------------------------------------------------------
  530. HRESULT OnInitDialog( HWND hDlg )
  531. {
  532.     LVCOLUMN column;
  533.     RECT     rctListView;
  534.     TCHAR    strHeader[255];
  535.     DWORD    dwVertScrollBar;
  536.     DWORD    dwListViewWidth;
  537.  
  538.     // Load and set the icon
  539.     HICON hIcon = LoadIcon( g_hInst, MAKEINTRESOURCE( IDI_MAIN ) );
  540.     SendMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  541.     SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  542.  
  543.     if( g_bHostPlayer )
  544.         SetWindowText( hDlg, TEXT("VoiceConnect (Session Host)") );
  545.     else
  546.         SetWindowText( hDlg, TEXT("VoiceConnect (Session Client)") );
  547.  
  548.     // Setup the listview
  549.     HWND hListView = GetDlgItem( hDlg, IDC_PEOPLE_LIST );
  550.     dwVertScrollBar = GetSystemMetrics( SM_CXVSCROLL );  
  551.     GetClientRect( hListView, &rctListView );
  552.     dwListViewWidth = rctListView.right - dwVertScrollBar;
  553.     column.mask     = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
  554.     column.fmt      = LVCFMT_LEFT;
  555.     column.iSubItem = -1;
  556.  
  557.     // Insert the Name column
  558.     _tcscpy( strHeader, TEXT("Name") );
  559.     column.cx         = dwListViewWidth * 5 / 10;
  560.     column.pszText    = strHeader;
  561.     column.cchTextMax = _tcslen( strHeader );
  562.     ListView_InsertColumn( hListView, 0, &column );
  563.  
  564.     // Insert the Status column
  565.     _tcscpy( strHeader, TEXT("Status") );
  566.     column.cx         = dwListViewWidth * 5 / 10;
  567.     column.pszText    = strHeader;
  568.     column.cchTextMax = _tcslen( strHeader );
  569.     ListView_InsertColumn( hListView, 1, &column );
  570.  
  571.     // Update the listbox 
  572.     PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  573.  
  574.     // Make a timer to update the listbox 
  575.     // 'Status' column every so often 
  576.     SetTimer( hDlg, 0, 250, NULL );
  577.  
  578.     return S_OK;
  579. }
  580.  
  581.  
  582.  
  583.  
  584. //-----------------------------------------------------------------------------
  585. // Name: DisplayPlayersInChat()
  586. // Desc: Displays the active players in the listview
  587. //-----------------------------------------------------------------------------
  588. HRESULT DisplayPlayersInChat( HWND hDlg )
  589. {
  590.     if( hDlg == NULL )
  591.         return S_OK;
  592.  
  593.     HRESULT hr;
  594.     LVITEM  lvItem;
  595.     HWND    hListView = GetDlgItem( hDlg, IDC_PEOPLE_LIST );
  596.     TCHAR   strStatus[32];
  597.     TCHAR   strNumberPlayers[32];
  598.     DWORD   dwNumPlayers;
  599.     APP_PLAYER_INFO* pPlayerInfo = NULL;
  600.  
  601.     // Remove all the players and re-add them in the player enum callback
  602.     ListView_DeleteAllItems( hListView );
  603.  
  604.     do
  605.     {
  606.         // Enum all players in the player ID array
  607.         dwNumPlayers = g_dwPlayersArraySize;
  608.         hr = g_pDP->EnumPlayersAndGroups( g_pPlayers, &dwNumPlayers, DPNENUM_PLAYERS );
  609.         if( SUCCEEDED(hr) )
  610.             break;
  611.  
  612.         if( hr == DPNERR_BUFFERTOOSMALL )
  613.         {
  614.             // Resize player pointer array     
  615.             g_dwPlayersArraySize += 10;
  616.             g_pPlayers   = (DPNID*) realloc( g_pPlayers, sizeof(DPNID)*g_dwPlayersArraySize );
  617.         }                
  618.     }         
  619.     while( hr == DPNERR_BUFFERTOOSMALL );
  620.  
  621.     if( FAILED(hr) )                    
  622.         return DXTRACE_ERR( TEXT("EnumPlayersAndGroups"), hr );
  623.  
  624.     for( DWORD i = 0; i<dwNumPlayers; i++ )
  625.     {
  626.         PLAYER_LOCK(); // enter player context CS
  627.  
  628.         do
  629.         {
  630.             // Get the player context accosicated with this DPNID
  631.             // Call GetPlayerContext() until it returns something other than DPNERR_NOTREADY
  632.             // DPNERR_NOTREADY will be returned if the callback thread has not 
  633.             // yet returned from DPN_MSGID_CREATE_PLAYER, which sets the player's context
  634.             hr = g_pDP->GetPlayerContext( g_pPlayers[i], (LPVOID*) &pPlayerInfo, 0);
  635.         } 
  636.         while( hr == DPNERR_NOTREADY ); 
  637.  
  638.         PLAYER_ADDREF( pPlayerInfo ); // addref player, since we are using it now
  639.         PLAYER_UNLOCK(); // leave player context CS
  640.  
  641.         if( FAILED(hr) || pPlayerInfo == NULL )
  642.         {
  643.             // The player who sent this may have gone away before this 
  644.             // message was handled, so just ignore it
  645.             continue;
  646.         }
  647.  
  648.         ZeroMemory( &lvItem, sizeof(lvItem) );
  649.  
  650.         // Add the item, saving the player's name and dpnid in the listview
  651.         lvItem.mask       = LVIF_TEXT | LVIF_PARAM;
  652.         lvItem.iItem      = 0;
  653.         lvItem.iSubItem   = 0;
  654.         lvItem.pszText    = pPlayerInfo->strPlayerName;
  655.         lvItem.lParam     = g_pPlayers[i];
  656.         lvItem.cchTextMax = _tcslen( pPlayerInfo->strPlayerName );
  657.         int nIndex = ListView_InsertItem( hListView, &lvItem );
  658.  
  659.         if( pPlayerInfo->bHalfDuplex )
  660.         {
  661.             _tcscpy( strStatus, TEXT("Can't talk") );
  662.         }
  663.         else
  664.         {
  665.             if( pPlayerInfo->bTalking )
  666.                 _tcscpy( strStatus, TEXT("Talking") );
  667.             else
  668.                 _tcscpy( strStatus, TEXT("Silent") );
  669.         }
  670.  
  671.         PLAYER_LOCK();
  672.         PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  673.         PLAYER_UNLOCK();
  674.  
  675.         // Start the player's status off as silent.  
  676.         lvItem.mask       = LVIF_TEXT;
  677.         lvItem.iItem      = nIndex;
  678.         lvItem.iSubItem   = 1;
  679.         lvItem.pszText    = strStatus;
  680.         lvItem.cchTextMax = _tcslen( strStatus );
  681.         ListView_SetItem( hListView, &lvItem );
  682.     }
  683.  
  684.     wsprintf( strNumberPlayers, TEXT("%d"), dwNumPlayers );
  685.     SetDlgItemText( hDlg, IDC_NUM_PLAYERS, strNumberPlayers );
  686.  
  687.     return S_OK;
  688. }
  689.  
  690.  
  691.  
  692.  
  693. //-----------------------------------------------------------------------------
  694. // Name: DirectPlayMessageHandler
  695. // Desc: Handler for DirectPlay messages.  This function is called by
  696. //       the DirectPlay message handler pool of threads, so be care of thread
  697. //       synchronization problems with shared memory
  698. //-----------------------------------------------------------------------------
  699. HRESULT WINAPI DirectPlayMessageHandler( PVOID pvUserContext, 
  700.                                          DWORD dwMessageId, 
  701.                                          PVOID pMsgBuffer )
  702. {
  703.     // Try not to stay in this message handler for too long, otherwise
  704.     // there will be a backlog of data.  The best solution is to 
  705.     // queue data as it comes in, and then handle it on other threads.
  706.     
  707.     // This function is called by the DirectPlay message handler pool of 
  708.     // threads, so be care of thread synchronization problems with shared memory
  709.  
  710.     switch( dwMessageId )
  711.     {
  712.         case DPN_MSGID_CREATE_PLAYER:
  713.         {
  714.             HRESULT hr;
  715.             PDPNMSG_CREATE_PLAYER pCreatePlayerMsg;
  716.             pCreatePlayerMsg = (PDPNMSG_CREATE_PLAYER)pMsgBuffer;
  717.  
  718.             // Create a new and fill in a APP_PLAYER_INFO
  719.             APP_PLAYER_INFO* pPlayerInfo = new APP_PLAYER_INFO;
  720.             ZeroMemory( pPlayerInfo, sizeof(APP_PLAYER_INFO) ); 
  721.             pPlayerInfo->lRefCount   = 1;
  722.             pPlayerInfo->dpnidPlayer = pCreatePlayerMsg->dpnidPlayer;
  723.  
  724.             // Get the peer info and extract its name
  725.             DWORD dwSize = 0;
  726.             DPN_PLAYER_INFO* pdpPlayerInfo = NULL;
  727.             hr = DPNERR_CONNECTING;
  728.             
  729.             // GetPeerInfo might return DPNERR_CONNECTING when connecting, 
  730.             // so just keep calling it if it does
  731.             while( hr == DPNERR_CONNECTING ) 
  732.                 hr = g_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0 );                                
  733.                 
  734.             if( hr == DPNERR_BUFFERTOOSMALL )
  735.             {
  736.                 pdpPlayerInfo = (DPN_PLAYER_INFO*) new BYTE[ dwSize ];
  737.                 ZeroMemory( pdpPlayerInfo, dwSize );
  738.                 pdpPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO);
  739.                 
  740.                 hr = g_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0 );
  741.                 if( SUCCEEDED(hr) )
  742.                 {
  743.                     // This stores a extra TCHAR copy of the player name for 
  744.                     // easier access.  This will be redundent copy since DPlay 
  745.                     // also keeps a copy of the player name in GetPeerInfo()
  746.                     DXUtil_ConvertWideStringToGeneric( pPlayerInfo->strPlayerName, 
  747.                                                        pdpPlayerInfo->pwszName, MAX_PLAYER_NAME );    
  748.                                                        
  749.                     if( (pdpPlayerInfo->dwPlayerFlags & DPNPLAYER_LOCAL) != 0 )
  750.                         g_LocalPlayerDPNID = pCreatePlayerMsg->dpnidPlayer;
  751.                 }
  752.                 
  753.                 SAFE_DELETE_ARRAY( pdpPlayerInfo );
  754.             }
  755.  
  756.             // Tell DirectPlay to store this pPlayerInfo 
  757.             // pointer in the pvPlayerContext.
  758.             pCreatePlayerMsg->pvPlayerContext = pPlayerInfo;
  759.  
  760.             // Post a message to the dialog thread to update the 
  761.             // UI.  This keeps the DirectPlay message handler 
  762.             // from blocking
  763.             if( g_hDlg != NULL )
  764.                 PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  765.             break;
  766.         }
  767.  
  768.         case DPN_MSGID_DESTROY_PLAYER:
  769.         {
  770.             PDPNMSG_DESTROY_PLAYER pDestroyPlayerMsg;
  771.             pDestroyPlayerMsg = (PDPNMSG_DESTROY_PLAYER)pMsgBuffer;
  772.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pDestroyPlayerMsg->pvPlayerContext;
  773.  
  774.             PLAYER_LOCK();                  // enter player context CS
  775.             PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  776.             PLAYER_UNLOCK();                // leave player context CS
  777.  
  778.             // Post a message to the dialog thread to update the 
  779.             // UI.  This keeps the DirectPlay message handler 
  780.             // from blocking
  781.             if( g_hDlg != NULL )
  782.                 PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  783.             break;
  784.         }
  785.  
  786.         case DPN_MSGID_TERMINATE_SESSION:
  787.         {
  788.             PDPNMSG_TERMINATE_SESSION pTerminateSessionMsg;
  789.             pTerminateSessionMsg = (PDPNMSG_TERMINATE_SESSION)pMsgBuffer;
  790.  
  791.             g_hrDialog = DPNERR_CONNECTIONLOST;
  792.             EndDialog( g_hDlg, 0 );
  793.             break;
  794.         }
  795.     }
  796.  
  797.     // Make sure the DirectPlay MessageHandler calls the CNetConnectWizard handler, 
  798.     // so it can be informed of messages such as DPN_MSGID_ENUM_HOSTS_RESPONSE.
  799.     if( g_pNetConnectWizard )
  800.         return g_pNetConnectWizard->MessageHandler( pvUserContext, dwMessageId, pMsgBuffer );
  801.     
  802.     return S_OK;
  803. }
  804.  
  805.  
  806.  
  807.  
  808. //-----------------------------------------------------------------------------
  809. // Name: DirectPlayLobbyMessageHandler
  810. // Desc: Handler for DirectPlay lobby messages.  This function is called by
  811. //       the DirectPlay lobby message handler pool of threads, so be careful of 
  812. //       thread synchronization problems with shared memory
  813. //-----------------------------------------------------------------------------
  814. HRESULT WINAPI DirectPlayLobbyMessageHandler( PVOID pvUserContext, 
  815.                                               DWORD dwMessageId, 
  816.                                               PVOID pMsgBuffer )
  817. {
  818.     switch( dwMessageId )
  819.     {
  820.         case DPL_MSGID_CONNECT:
  821.         {
  822.             PDPL_MESSAGE_CONNECT pConnectMsg;
  823.             pConnectMsg = (PDPL_MESSAGE_CONNECT)pMsgBuffer;
  824.  
  825.             // The CNetConnectWizard will handle this message for us,
  826.             // so there is nothing we need to do here for this simple
  827.             // sample.
  828.             break;
  829.         }
  830.  
  831.         case DPL_MSGID_DISCONNECT:
  832.         {
  833.             PDPL_MESSAGE_DISCONNECT pDisconnectMsg;
  834.             pDisconnectMsg = (PDPL_MESSAGE_DISCONNECT)pMsgBuffer;
  835.  
  836.             // We should free any data associated with the lobby 
  837.             // client here, but there is none.
  838.             break;
  839.         }
  840.  
  841.         case DPL_MSGID_RECEIVE:
  842.         {
  843.             PDPL_MESSAGE_RECEIVE pReceiveMsg;
  844.             pReceiveMsg = (PDPL_MESSAGE_RECEIVE)pMsgBuffer;
  845.  
  846.             // The lobby client sent us data.  This sample doesn't
  847.             // expected data from the client, but it is useful 
  848.             // for more complex apps.
  849.             break;
  850.         }
  851.  
  852.         case DPL_MSGID_CONNECTION_SETTINGS:
  853.         {
  854.             PDPL_MESSAGE_CONNECTION_SETTINGS pConnectionStatusMsg;
  855.             pConnectionStatusMsg = (PDPL_MESSAGE_CONNECTION_SETTINGS)pMsgBuffer;
  856.  
  857.             // The lobby client has changed the connection settings.  
  858.             // This simple sample doesn't handle this, but more complex apps may
  859.             // want to.
  860.             break;
  861.         }
  862.     }
  863.  
  864.     // Make sure the DirectPlay MessageHandler calls the CNetConnectWizard handler, 
  865.     // so the wizard can be informed of lobby messages such as DPL_MSGID_CONNECT
  866.     if( g_pNetConnectWizard )
  867.         return g_pNetConnectWizard->LobbyMessageHandler( pvUserContext, dwMessageId, 
  868.                                                          pMsgBuffer );
  869.     
  870.     return S_OK;
  871. }
  872.  
  873.  
  874.  
  875.  
  876. //-----------------------------------------------------------------------------
  877. // Name: DirectPlayVoiceServerMessageHandler()
  878. // Desc: The callback for DirectPlayVoice server messages.  
  879. //-----------------------------------------------------------------------------
  880. HRESULT CALLBACK DirectPlayVoiceServerMessageHandler( LPVOID lpvUserContext, DWORD dwMessageType,
  881.                                                       LPVOID lpMessage )
  882. {
  883.     // This simple sample doesn't respond to any server messages
  884.     return S_OK;
  885. }
  886.  
  887.  
  888.  
  889.  
  890. //-----------------------------------------------------------------------------
  891. // Name: DirectPlayVoiceClientMessageHandler()
  892. // Desc: The callback for DirectPlayVoice client messages.  
  893. //       This handles client messages and updates the UI the whenever a client 
  894. //       starts or stops talking.  
  895. //-----------------------------------------------------------------------------
  896. HRESULT CALLBACK DirectPlayVoiceClientMessageHandler( LPVOID lpvUserContext, DWORD dwMessageType,
  897.                                                       LPVOID lpMessage )
  898. {
  899.     // Try not to stay in this message handler for too long, otherwise
  900.     // there will be a backlog of data.  The best solution is to 
  901.     // queue data as it comes in, and then handle it on other threads.
  902.     
  903.     // This function is called by the DirectPlay message handler pool of 
  904.     // threads, so be care of thread synchronization problems with shared memory
  905.     HRESULT hr;
  906.     HWND hDlg = (HWND) lpvUserContext;
  907.  
  908.     switch( dwMessageType )
  909.     {
  910.         case DVMSGID_CREATEVOICEPLAYER:
  911.             {
  912.                 DVMSG_CREATEVOICEPLAYER* pCreateVoicePlayerMsg = (DVMSG_CREATEVOICEPLAYER*) lpMessage;
  913.                 APP_PLAYER_INFO* pPlayerInfo = NULL;
  914.  
  915.                 PLAYER_LOCK(); // enter player context CS
  916.  
  917.                 // Get the player context accosicated with this DPNID
  918.                 hr = g_pDP->GetPlayerContext( pCreateVoicePlayerMsg->dvidPlayer, 
  919.                                               (LPVOID* const) &pPlayerInfo,
  920.                                               0);
  921.  
  922.                 if( FAILED(hr) || pPlayerInfo == NULL )
  923.                 {
  924.                     // The player who sent this may have gone away before this 
  925.                     // message was handled, so just ignore it
  926.                     PLAYER_UNLOCK();
  927.                     break;
  928.                 }
  929.  
  930.                 PLAYER_ADDREF( pPlayerInfo ); // addref player, to be used by the voice layer
  931.                 PLAYER_UNLOCK(); // leave player context CS
  932.  
  933.                 pPlayerInfo->bHalfDuplex = ((pCreateVoicePlayerMsg->dwFlags & DVPLAYERCAPS_HALFDUPLEX) != 0);
  934.  
  935.                 // Set voice context value
  936.                 pCreateVoicePlayerMsg->pvPlayerContext = pPlayerInfo;
  937.  
  938.                 // Post a message to the dialog thread to update the 
  939.                 // UI.  This keeps the DirectPlay message handler 
  940.                 // from blocking
  941.                 if( g_hDlg != NULL )
  942.                     PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  943.  
  944.                 // We're leaving the extra reference, voice will own that reference
  945.             }
  946.             break;
  947.  
  948.         case DVMSGID_DELETEVOICEPLAYER:
  949.         {
  950.             DVMSG_DELETEVOICEPLAYER* pMsg = (DVMSG_DELETEVOICEPLAYER*) lpMessage;
  951.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvPlayerContext;
  952.  
  953.             // Don't update the dlg if this message is for the local 
  954.             // client since the dlg will be gone.
  955.             if( pMsg->dvidPlayer != g_LocalPlayerDPNID )
  956.             {
  957.                 // Post a message to the dialog thread to update the 
  958.                 // UI.  This keeps the DirectPlay message handler 
  959.                 // from blocking
  960.                 if( hDlg != NULL )
  961.                     PostMessage( hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  962.             }
  963.  
  964.             // Release our extra reference on the player info that we have for the voice
  965.             // context value.  
  966.             //
  967.             PLAYER_LOCK();
  968.             PLAYER_RELEASE( pPlayerInfo );  
  969.             PLAYER_UNLOCK();
  970.             break;
  971.         }            
  972.  
  973.  
  974.         case DVMSGID_SESSIONLOST:
  975.             g_hrDialog = DPNERR_CONNECTIONLOST;
  976.             EndDialog( hDlg, 0 );
  977.             break;
  978.  
  979.         case DVMSGID_HOSTMIGRATED:
  980.         {
  981.             DVMSG_HOSTMIGRATED* pMsg = (DVMSG_HOSTMIGRATED*) lpMessage;
  982.  
  983.             if( pMsg->pdvServerInterface != NULL )
  984.             {           
  985.                 // If we keep the pMsg->pdvServerInterface pointer around, then
  986.                 // we must AddRef() it.  The CNetVoice::HostMigrate() automatically
  987.                 // does this for us.
  988.                 g_pNetVoice->HostMigrate( pMsg->pdvServerInterface );
  989.  
  990.                 g_bHostPlayer = TRUE;
  991.                 SetWindowText( hDlg, TEXT("VoiceConnect (Session Host)") );
  992.             }
  993.             break;
  994.         }
  995.  
  996.         case DVMSGID_GAINFOCUS:
  997.         case DVMSGID_LOSTFOCUS:
  998.         {
  999.             TCHAR strWindowName[MAX_PATH];
  1000.             wsprintf( strWindowName, TEXT("%s%s%s"), g_strAppName,
  1001.                 (g_bHostPlayer)                      ? TEXT(" (Session Host)") : TEXT(""),
  1002.                 (dwMessageType == DVMSGID_LOSTFOCUS) ? TEXT(" (Focus Lost)") : TEXT("") );
  1003.  
  1004.             SetWindowText( hDlg, strWindowName );
  1005.             break;
  1006.         }
  1007.  
  1008.         case DVMSGID_RECORDSTART:             
  1009.         { 
  1010.             DVMSG_RECORDSTART* pMsg = (DVMSG_RECORDSTART*) lpMessage;
  1011.             SetPlayerTalking( (APP_PLAYER_INFO*) pMsg->pvLocalPlayerContext, TRUE );
  1012.             break;
  1013.         }
  1014.         case DVMSGID_RECORDSTOP:             
  1015.         {
  1016.             DVMSG_RECORDSTOP* pMsg = (DVMSG_RECORDSTOP*) lpMessage;
  1017.             SetPlayerTalking( (APP_PLAYER_INFO*) pMsg->pvLocalPlayerContext, FALSE );
  1018.             break;
  1019.         }
  1020.         case DVMSGID_PLAYERVOICESTART:
  1021.         {
  1022.             DVMSG_PLAYERVOICESTART* pMsg = (DVMSG_PLAYERVOICESTART*) lpMessage;
  1023.             SetPlayerTalking( (APP_PLAYER_INFO*) pMsg->pvPlayerContext, TRUE );
  1024.             break;
  1025.         }
  1026.  
  1027.         case DVMSGID_PLAYERVOICESTOP:
  1028.         {
  1029.             DVMSG_PLAYERVOICESTOP* pMsg = (DVMSG_PLAYERVOICESTOP*) lpMessage;
  1030.             SetPlayerTalking( (APP_PLAYER_INFO*) pMsg->pvPlayerContext, FALSE );            
  1031.             break;
  1032.         }
  1033.     }
  1034.  
  1035.     return S_OK;
  1036. }
  1037.  
  1038.  
  1039.  
  1040.  
  1041. //-----------------------------------------------------------------------------
  1042. // Name: SetPlayerTalking()
  1043. // Desc: Set player talking flag
  1044. //-----------------------------------------------------------------------------
  1045. void SetPlayerTalking( APP_PLAYER_INFO* pPlayerInfo, BOOL bTalking )
  1046. {
  1047.     if( pPlayerInfo )
  1048.         pPlayerInfo->bTalking = bTalking;     
  1049. }
  1050.  
  1051.  
  1052.  
  1053.  
  1054. //-----------------------------------------------------------------------------
  1055. // Name: VoiceConfigDlgProc()
  1056. // Desc: Prompt the user for DirectPlayVoice setup options
  1057. //-----------------------------------------------------------------------------
  1058. INT_PTR CALLBACK VoiceConfigDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  1059. {
  1060.     DWORD dwSliderPos;
  1061.  
  1062.     switch( msg ) 
  1063.     {
  1064.         case WM_INITDIALOG:
  1065.             // Set the range on the sliders
  1066.             SendDlgItemMessage( hDlg, IDC_PLAYBACK_SLIDER,       TBM_SETRANGE, FALSE, MAKELONG( 0, 100 ) );
  1067.             SendDlgItemMessage( hDlg, IDC_RECORD_SLIDER,         TBM_SETRANGE, FALSE, MAKELONG( 0, 100 ) );
  1068.             SendDlgItemMessage( hDlg, IDC_QUALITY_SLIDER,        TBM_SETRANGE, FALSE, MAKELONG( DVBUFFERQUALITY_MIN, DVBUFFERQUALITY_MAX ) );
  1069.             SendDlgItemMessage( hDlg, IDC_THRESHOLD_SLIDER,    TBM_SETRANGE, FALSE, MAKELONG( DVTHRESHOLD_MIN,  DVTHRESHOLD_MAX ) );
  1070.             SendDlgItemMessage( hDlg, IDC_AGGRESSIVENESS_SLIDER, TBM_SETRANGE, FALSE, MAKELONG( DVBUFFERAGGRESSIVENESS_MIN, DVBUFFERAGGRESSIVENESS_MAX ) );
  1071.  
  1072.             // Setup the dialog based on the globals 
  1073.  
  1074.             // Set the playback controls
  1075.             if( g_dvClientConfig.lPlaybackVolume == DVPLAYBACKVOLUME_DEFAULT )
  1076.             {
  1077.                 CheckRadioButton( hDlg, IDC_PLAYBACK_DEFAULT, IDC_PLAYBACK_SET, IDC_PLAYBACK_DEFAULT );
  1078.             }
  1079.             else
  1080.             {
  1081.                 dwSliderPos = (DWORD) ( ( g_dvClientConfig.lPlaybackVolume - DSBVOLUME_MIN ) * 
  1082.                                           100.0f / (DSBVOLUME_MAX-DSBVOLUME_MIN) );
  1083.                 CheckRadioButton( hDlg, IDC_PLAYBACK_DEFAULT, IDC_PLAYBACK_SET, IDC_PLAYBACK_SET );
  1084.                 SendDlgItemMessage( hDlg, IDC_PLAYBACK_SLIDER, TBM_SETPOS, TRUE, dwSliderPos );
  1085.             }
  1086.  
  1087.             // Set the record controls
  1088.             if( g_dvClientConfig.dwFlags & DVCLIENTCONFIG_AUTORECORDVOLUME )
  1089.             {
  1090.                 CheckRadioButton( hDlg, IDC_RECORD_DEFAULT, IDC_RECORD_AUTO, IDC_RECORD_AUTO );
  1091.             }
  1092.             else if( g_dvClientConfig.lRecordVolume == DVPLAYBACKVOLUME_DEFAULT )
  1093.             {
  1094.                 CheckRadioButton( hDlg, IDC_RECORD_DEFAULT, IDC_RECORD_AUTO, IDC_RECORD_DEFAULT );
  1095.             }
  1096.             else
  1097.             {
  1098.                 dwSliderPos = (DWORD) ( ( g_dvClientConfig.lRecordVolume - DSBVOLUME_MIN ) * 
  1099.                                           100.0f / (DSBVOLUME_MAX-DSBVOLUME_MIN) );
  1100.                 CheckRadioButton( hDlg, IDC_RECORD_DEFAULT, IDC_RECORD_AUTO, IDC_RECORD_SET );
  1101.                 SendDlgItemMessage( hDlg, IDC_RECORD_SLIDER, TBM_SETPOS, TRUE, dwSliderPos );
  1102.             }
  1103.  
  1104.             // Set the threshold controls
  1105.             if( g_dvClientConfig.dwFlags & DVCLIENTCONFIG_AUTOVOICEACTIVATED )
  1106.             {
  1107.                 CheckRadioButton( hDlg, IDC_THRESHOLD_DEFAULT, IDC_THRESHOLD_AUTO, IDC_THRESHOLD_AUTO );
  1108.             }
  1109.             else if( g_dvClientConfig.dwThreshold == DVTHRESHOLD_DEFAULT )
  1110.             {
  1111.                 CheckRadioButton( hDlg, IDC_THRESHOLD_DEFAULT, IDC_THRESHOLD_AUTO, IDC_THRESHOLD_DEFAULT );
  1112.             }
  1113.             else
  1114.             {
  1115.                 CheckRadioButton( hDlg, IDC_THRESHOLD_DEFAULT, IDC_THRESHOLD_AUTO, IDC_THRESHOLD_SET );
  1116.                 SendDlgItemMessage( hDlg, IDC_THRESHOLD_SLIDER, TBM_SETPOS, TRUE, g_dvClientConfig.dwThreshold );
  1117.             }
  1118.  
  1119.             // Set the quality controls
  1120.             if( g_dvClientConfig.dwBufferQuality == DVBUFFERQUALITY_DEFAULT )
  1121.             {
  1122.                 CheckRadioButton( hDlg, IDC_QUALITY_DEFAULT, IDC_QUALITY_SET, IDC_QUALITY_DEFAULT );
  1123.             }
  1124.             else
  1125.             {
  1126.                 CheckRadioButton( hDlg, IDC_QUALITY_DEFAULT, IDC_QUALITY_SET, IDC_QUALITY_SET );
  1127.                 SendDlgItemMessage( hDlg, IDC_QUALITY_SLIDER, TBM_SETPOS, TRUE, g_dvClientConfig.dwBufferQuality );
  1128.             }
  1129.  
  1130.             // Set the aggressiveness controls
  1131.             if( g_dvClientConfig.dwBufferAggressiveness == DVBUFFERAGGRESSIVENESS_DEFAULT )
  1132.             {
  1133.                 CheckRadioButton( hDlg, IDC_AGGRESSIVENESS_DEFAULT, IDC_AGGRESSIVENESS_SET, IDC_AGGRESSIVENESS_DEFAULT );
  1134.             }
  1135.             else
  1136.             {
  1137.                 CheckRadioButton( hDlg, IDC_AGGRESSIVENESS_DEFAULT, IDC_AGGRESSIVENESS_SET, IDC_AGGRESSIVENESS_SET );
  1138.                 SendDlgItemMessage( hDlg, IDC_AGGRESSIVENESS_SLIDER, TBM_SETPOS, TRUE, g_dvClientConfig.dwBufferAggressiveness );
  1139.             }
  1140.  
  1141.             if( !g_bHostPlayer || g_bVoiceSessionInProgress )
  1142.             {
  1143.                 // We are are not the host player then disable all the server only options 
  1144.                 EnableWindow( GetDlgItem( hDlg, IDC_COMPRESSION_COMBO ), FALSE );
  1145.                 EnableWindow( GetDlgItem( hDlg, IDC_SESSIONCOMPRESION_GROUP ), FALSE );
  1146.             }
  1147.             else
  1148.             {
  1149.                 VoiceConfigEnumCompressionCodecs( hDlg );   
  1150.                 EnableWindow( GetDlgItem( hDlg, IDCANCEL ), FALSE );
  1151.             }
  1152.  
  1153.             return TRUE;
  1154.  
  1155.         case WM_NOTIFY:
  1156.             #ifndef NM_RELEASEDCAPTURE
  1157.                 #define NM_RELEASEDCAPTURE (NM_FIRST-16)
  1158.             #endif
  1159.             if( ((LPNMHDR) lParam)->code == NM_RELEASEDCAPTURE )
  1160.             {
  1161.                 // If this is a release capture from a slider, then automatically check 
  1162.                 // its 'Set' radio button.
  1163.                 switch( ((LPNMHDR) lParam)->idFrom )
  1164.                 {
  1165.                 case IDC_PLAYBACK_SLIDER:
  1166.                     CheckRadioButton( hDlg, IDC_PLAYBACK_DEFAULT, IDC_PLAYBACK_SET, IDC_PLAYBACK_SET );
  1167.                     break;
  1168.     
  1169.                 case IDC_RECORD_SLIDER:
  1170.                     CheckRadioButton( hDlg, IDC_RECORD_DEFAULT, IDC_RECORD_AUTO, IDC_RECORD_SET );
  1171.                     break;
  1172.     
  1173.                 case IDC_THRESHOLD_SLIDER:
  1174.                     CheckRadioButton( hDlg, IDC_THRESHOLD_DEFAULT, IDC_THRESHOLD_AUTO, IDC_THRESHOLD_SET );
  1175.                     break;
  1176.     
  1177.                 case IDC_QUALITY_SLIDER:
  1178.                     CheckRadioButton( hDlg, IDC_QUALITY_DEFAULT, IDC_QUALITY_SET, IDC_QUALITY_SET );
  1179.                     break;
  1180.     
  1181.                 case IDC_AGGRESSIVENESS_SLIDER:
  1182.                     CheckRadioButton( hDlg, IDC_AGGRESSIVENESS_DEFAULT, IDC_AGGRESSIVENESS_SET, IDC_AGGRESSIVENESS_SET );
  1183.                     break;
  1184.                 }
  1185.             }
  1186.             return TRUE;            
  1187.  
  1188.         case WM_COMMAND:
  1189.             switch( LOWORD(wParam) )
  1190.             {
  1191.                 case IDOK:
  1192.                     VoiceConfigDlgOnOK( hDlg );
  1193.                     return TRUE;
  1194.  
  1195.                 case IDCANCEL:
  1196.                     EndDialog( hDlg, IDCANCEL );
  1197.                     return TRUE;
  1198.             }
  1199.             break;
  1200.  
  1201.         case WM_DESTROY:
  1202.         {
  1203.             GUID* pGuid;
  1204.             int nCount = (int)SendDlgItemMessage( hDlg, IDC_COMPRESSION_COMBO, CB_GETCOUNT, 0, 0 );
  1205.             for( int i=0; i<nCount; i++ )
  1206.             {
  1207.                 pGuid = (LPGUID) SendDlgItemMessage( hDlg, IDC_COMPRESSION_COMBO, CB_GETITEMDATA, i, 0 );
  1208.                 SAFE_DELETE( pGuid );
  1209.             }
  1210.             break;
  1211.         }
  1212.     }
  1213.  
  1214.     return FALSE; // Didn't handle message
  1215. }
  1216.  
  1217.  
  1218.  
  1219.  
  1220. //-----------------------------------------------------------------------------
  1221. // Name: VoiceConfigEnumCompressionCodecs()
  1222. // Desc: Asks DirectPlayVoice what voice compression codecs are availible
  1223. //       and fills the combo box thier names and GUIDs.
  1224. //-----------------------------------------------------------------------------
  1225. HRESULT VoiceConfigEnumCompressionCodecs( HWND hDlg )
  1226. {
  1227.     LPDIRECTPLAYVOICECLIENT pVoiceClient        = NULL;
  1228.     LPDVCOMPRESSIONINFO     pdvCompressionInfo  = NULL;
  1229.     LPGUID  pGuid         = NULL;
  1230.     LPBYTE  pBuffer       = NULL;
  1231.     DWORD   dwSize        = 0;
  1232.     DWORD   dwNumElements = 0;
  1233.     HWND    hPulldown     = GetDlgItem( hDlg, IDC_COMPRESSION_COMBO );
  1234.     HRESULT hr;
  1235.     LONG    lIndex;
  1236.     LONG    lFirst;
  1237.  
  1238.     CoInitializeEx( NULL, COINIT_MULTITHREADED );
  1239.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlayVoiceClient, NULL, 
  1240.                                        CLSCTX_INPROC_SERVER, IID_IDirectPlayVoiceClient, 
  1241.                                        (VOID**) &pVoiceClient ) ) )
  1242.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  1243.  
  1244.     hr = pVoiceClient->GetCompressionTypes( pBuffer, &dwSize, &dwNumElements, 0 );
  1245.     if( hr != DVERR_BUFFERTOOSMALL && FAILED(hr) )
  1246.         return DXTRACE_ERR( TEXT("GetCompressionTypes"), hr );
  1247.  
  1248.     pBuffer = new BYTE[dwSize];
  1249.     if( FAILED( hr = pVoiceClient->GetCompressionTypes( pBuffer, &dwSize, 
  1250.                                                         &dwNumElements, 0 ) ) )
  1251.         return DXTRACE_ERR( TEXT("GetCompressionTypes"), hr );
  1252.  
  1253.     SAFE_RELEASE( pVoiceClient );
  1254.     CoUninitialize();
  1255.  
  1256.     pdvCompressionInfo = (LPDVCOMPRESSIONINFO) pBuffer;
  1257.     for( DWORD dwIndex = 0; dwIndex < dwNumElements; dwIndex++ )
  1258.     {
  1259.         TCHAR strName[MAX_PATH];
  1260.         DXUtil_ConvertWideStringToGeneric( strName, 
  1261.                                            pdvCompressionInfo[dwIndex].lpszName );
  1262.  
  1263.         lIndex = (LONG)SendMessage( hPulldown, CB_ADDSTRING, 0, (LPARAM) strName );
  1264.  
  1265.         pGuid = new GUID;
  1266.         (*pGuid) = pdvCompressionInfo[dwIndex].guidType;
  1267.         SendMessage( hPulldown, CB_SETITEMDATA, lIndex, (LPARAM) pGuid );
  1268.  
  1269.         if( pdvCompressionInfo[dwIndex].guidType == DPVCTGUID_SC03 )
  1270.             lFirst = lIndex;
  1271.     }
  1272.  
  1273.     SAFE_DELETE_ARRAY( pBuffer );
  1274.     SendMessage( hPulldown, CB_SETCURSEL, lFirst, 0 );
  1275.  
  1276.     return S_OK;
  1277. }
  1278.  
  1279.  
  1280.  
  1281.  
  1282. //-----------------------------------------------------------------------------
  1283. // Name: VoiceConfigDlgOnOK()
  1284. // Desc: Figure out all the DirectPlayVoice setup params from the dialog box,
  1285. //       and store them in global vars.
  1286. //-----------------------------------------------------------------------------
  1287. VOID VoiceConfigDlgOnOK( HWND hDlg )
  1288. {
  1289.     DWORD dwSliderPos;
  1290.  
  1291.     g_dvClientConfig.dwFlags = 0;
  1292.  
  1293.     // Figure out the playback params
  1294.     if( IsDlgButtonChecked( hDlg, IDC_PLAYBACK_DEFAULT ) )
  1295.     {
  1296.         g_dvClientConfig.lPlaybackVolume = DVPLAYBACKVOLUME_DEFAULT;
  1297.     }
  1298.     else 
  1299.     {
  1300.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_PLAYBACK_SLIDER, TBM_GETPOS, 0, 0 );
  1301.         g_dvClientConfig.lPlaybackVolume = DSBVOLUME_MIN + (LONG) ( dwSliderPos / 100.0f * 
  1302.                                                                     (DSBVOLUME_MAX-DSBVOLUME_MIN) );
  1303.     }
  1304.  
  1305.     // Figure out the record params
  1306.     if( IsDlgButtonChecked( hDlg, IDC_RECORD_AUTO ) )
  1307.     {
  1308.         g_dvClientConfig.lRecordVolume = 0;
  1309.         g_dvClientConfig.dwFlags       |= DVCLIENTCONFIG_AUTORECORDVOLUME;
  1310.     }
  1311.     else if( IsDlgButtonChecked( hDlg, IDC_RECORD_DEFAULT ) )
  1312.     {
  1313.         g_dvClientConfig.lRecordVolume = DVPLAYBACKVOLUME_DEFAULT;
  1314.     }
  1315.     else 
  1316.     {
  1317.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_RECORD_SLIDER, TBM_GETPOS, 0, 0 );
  1318.         g_dvClientConfig.lRecordVolume = DSBVOLUME_MIN + (LONG) ( dwSliderPos / 100.0f * 
  1319.                                                                   (DSBVOLUME_MAX-DSBVOLUME_MIN) );
  1320.     }
  1321.  
  1322.     // Figure out the threshold params
  1323.     if( IsDlgButtonChecked( hDlg, IDC_THRESHOLD_AUTO ) )
  1324.     {
  1325.         g_dvClientConfig.dwThreshold = DVTHRESHOLD_UNUSED;
  1326.         g_dvClientConfig.dwFlags       |= DVCLIENTCONFIG_AUTOVOICEACTIVATED;
  1327.     }
  1328.     else if( IsDlgButtonChecked( hDlg, IDC_THRESHOLD_DEFAULT ) )
  1329.     {
  1330.         g_dvClientConfig.dwThreshold = DVTHRESHOLD_DEFAULT;
  1331.         g_dvClientConfig.dwFlags       |= DVCLIENTCONFIG_MANUALVOICEACTIVATED;
  1332.     }
  1333.     else 
  1334.     {
  1335.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_THRESHOLD_SLIDER, TBM_GETPOS, 0, 0 );
  1336.         g_dvClientConfig.dwThreshold = dwSliderPos;
  1337.         g_dvClientConfig.dwFlags       |= DVCLIENTCONFIG_MANUALVOICEACTIVATED;
  1338.     }
  1339.  
  1340.     // Figure out the quality params
  1341.     if( IsDlgButtonChecked( hDlg, IDC_QUALITY_DEFAULT ) )
  1342.     {
  1343.         g_dvClientConfig.dwBufferQuality = DVBUFFERQUALITY_DEFAULT;
  1344.     }
  1345.     else 
  1346.     {
  1347.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_QUALITY_SLIDER, TBM_GETPOS, 0, 0 );
  1348.         g_dvClientConfig.dwBufferQuality = dwSliderPos;
  1349.     }
  1350.  
  1351.     // Figure out the aggressiveness params
  1352.     if( IsDlgButtonChecked( hDlg, IDC_AGGRESSIVENESS_DEFAULT ) )
  1353.     {
  1354.         g_dvClientConfig.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT;
  1355.     }
  1356.     else 
  1357.     {
  1358.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_AGGRESSIVENESS_SLIDER, TBM_GETPOS, 0, 0 );
  1359.         g_dvClientConfig.dwBufferAggressiveness = dwSliderPos;
  1360.     }
  1361.  
  1362.     if( g_bHostPlayer )
  1363.     {
  1364.         // Figure out the compression codec
  1365.         LONG lCurSelection;
  1366.         LPGUID pGuidCT;
  1367.  
  1368.         lCurSelection = (LONG)SendDlgItemMessage( hDlg, IDC_COMPRESSION_COMBO, CB_GETCURSEL, 0, 0 );
  1369.         if( lCurSelection != CB_ERR )
  1370.         {
  1371.             pGuidCT = (LPGUID) SendDlgItemMessage( hDlg, IDC_COMPRESSION_COMBO, 
  1372.                                                    CB_GETITEMDATA, lCurSelection, 0 );
  1373.             if( pGuidCT != NULL )
  1374.                 g_guidDVSessionCT = (*pGuidCT);
  1375.         }
  1376.     }
  1377.  
  1378.     EndDialog( hDlg, IDOK );
  1379. }
  1380.  
  1381.  
  1382.  
  1383.  
  1384.